﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Security.Cryptography;




namespace TB_Artifact_Project
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        /*  Initialize RSA and Get Private and Public KeyInfo in paramters.
            It is outside so the public and private keys are the same for 
            the whole session of the program being open. */
        RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
        

        bool showEncryptionComplete;

        /// <summary>
        /// This method is more or less the core of the program. 
        /// </summary>
        /// <param name="x">This parameter dictates which method of encryption is to be used.
        /// 1 = TripleDES
        /// 2 = MD5
        /// 3 = RSA
        /// 4 = HMACSHA1
        /// </param>
        private void encrypt(int x)
        {

            showEncryptionComplete = true;
            
            // If the user has not selected a file to use by clicking "Open" in the menu strip, then have them
            // choose one and take put the full path and name of the file in fileIn.
            string fileIn = (filenameLabel.Text == "") ? getFileName() : filenameLabel.Text;
            filenameLabel.Text = fileIn;
            
            if (x == 1)
            {
                // TripleDES encrypts text in file 
                infolabel.Text = "Calculating TripleDES Encryption";
                // First we are going to open the file streams                    
                FileStream fsIn = new FileStream(fileIn, FileMode.Open, FileAccess.Read);
                    
 
                // Then we are going to derive a Key and an IV from the Password and create an algorithm
                PasswordDeriveBytes pdb = new PasswordDeriveBytes(getKey(), new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d,  0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
 
                TripleDES alg = TripleDES.Create();
 
                alg.Key = pdb.GetBytes(24);
                alg.IV = pdb.GetBytes(8);
 
                // Now create a crypto stream through which we are going to be pumping data.
                // Our fileOut is going to be receiving the encrypted bytes.
                DialogResult result = saveFileDialog1.ShowDialog();
                if (result == DialogResult.OK)
                {
                        
                    string fileOut = saveFileDialog1.FileName;
                    infolabel.Text = "Encrypting" + fileOut.Substring(fileOut.LastIndexOf('\\') + 1, fileOut.Length - fileOut.LastIndexOf('\\') - 1);
                    FileStream fsOut = new FileStream(fileOut, FileMode.OpenOrCreate, FileAccess.Write);
                    CryptoStream cs = new CryptoStream(fsOut, alg.CreateEncryptor(), CryptoStreamMode.Write);

                    // Now will will initialize a buffer and will be processing the input file in chunks.
                    // This is done to avoid reading the whole file (which can be huge) into memory.
                    int bufferLen = 4096;
                    byte[] buffer = new byte[bufferLen];
                    int bytesRead;

                    do
                    {
                        // read a chunk of data from the input file
                        bytesRead = fsIn.Read(buffer, 0, bufferLen);

                        // encrypt it
                        cs.Write(buffer, 0, bytesRead);

                    } while (bytesRead != 0);

                    // close everything
                    cs.Close(); // this will also close the unrelying fsOut stream
                    fsIn.Close();

                    
                }
      

            }
            else if (x == 2)
            {
                // MD5 creates hash of file.
                infolabel.Text = "Calculating MD5 Hash";
                MD5 md5 = MD5.Create();
                byte[] inputBytes = File.ReadAllBytes(fileIn);
                byte[] hash = md5.ComputeHash(inputBytes);
                string temp = "The MD5 Hash of \"" + filenameLabel.Text.Substring(filenameLabel.Text.LastIndexOf('\\')+1, filenameLabel.Text.Length-filenameLabel.Text.LastIndexOf('\\')-1) + "\" = " + byteToString(hash);
                if(!saveEncryption(temp))
                {
                    textBox1.Text = temp;
                }
                infolabel.Text = "";
            }
            else if (x == 3)
            {
                // RSA encrypts a file.
                
                try
                {
                    
                   /* 
                    For future searches regarding RSA bad length exceptions...

                    You can calculate the max number of bytes which can be encrypted 
                    with a particular key size with the following:

                    ((KeySize - 384) / 8) + 37

                    However, if the optimal asymmetric encryption padding (OAEP) parameter is true, 
                    the following can be used to calculate the max bytes:

                    ((KeySize - 384) / 8) + 7

                    The legal key sizes are 384 thru 16384 with a skip size of 8.
                    */


                    // This section is where I take all the clear data and encrypt it a small amount at a time.
                    // This is because RSA is not made to encrypt a large amount of data. It's basically meant to encrypt
                    // keys/passwords with a public key.
                    byte[] clearData = File.ReadAllBytes(fileIn);
                    
                    int len = ((RSA.KeySize - 384) / 8) + 37;
                    byte[] result = new byte[len];
                    int index = 0;
                    string encData = "";
                    int remainder = clearData.Length % len;
                    while(index <= clearData.Length-1)
                    {
                        if (remainder > 0)
                        {
                            for (int i = 0; i < remainder; i++)
                            {
                                result[i] = clearData[i];
                                index++;
                            }
                            remainder -= remainder;
                        }
                        else
                        {
                            for (int i = 0; i < len && index < clearData.Length; i++)
                            {
                                result[i] = clearData[index];
                                index++;
                            }
                        }
                        
                        encData += byteToString(RSA.Encrypt(result, false));
                        
                    }

                    
                    // If the user decides to not to save the encryption to a file and does not click "Cancel"
                    // then the user wants to output the encryption to the textBox1
                    if (!saveEncryption(encData))
                    {
                        textBox1.Text = "The RSA encryption of \"" + filenameLabel.Text.Substring(filenameLabel.Text.LastIndexOf('\\') + 1, filenameLabel.Text.Length - filenameLabel.Text.LastIndexOf('\\') - 1) + "\" = " + encData;

                    }

                    
                }
                //Catch and display a CryptographicException  
                //to the console.
                catch (CryptographicException e)
                {
                    infolabel.Text = e.Message;
                    
                }

            }
            else
            {
                // HMACSHA1 creates hash of file.
                infolabel.Text = "Calculating HMACSHA1 Hash";
                HMACSHA1 hmacsha1 = new HMACSHA1(getKey());
                byte[] hash = hmacsha1.ComputeHash(File.ReadAllBytes(getFileName()));
                string temp = "The HMACSHA1 Hash of \"" + filenameLabel.Text.Substring(filenameLabel.Text.LastIndexOf('\\') + 1, filenameLabel.Text.Length - filenameLabel.Text.LastIndexOf('\\') - 1) + "\" = " + byteToString(hash);
                if (!saveEncryption(temp))
                {
                    textBox1.Text = temp;
                }
                infolabel.Text = "";
            }

            infolabel.Text = showEncryptionComplete ? "The Encryption Process Is Complete!" : "Please Select An Action";
        
        }


        /// <summary>
        /// This method asks the user if he/she wants to save the encryption.
        /// </summary>
        /// <param name="s"> This is the encrypted text.</param>
        /// <returns> Returns a boolean. It's used to check whether or not the program
        /// should output the encryption to the textBox1.</returns>
        private bool saveEncryption(string s)
        {
            DialogResult result1 = MessageBox.Show("Would you like to save your encryption?", "Save???", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);

            if (result1 == DialogResult.Yes)
            {
                infolabel.Text = "Saving Encrypted File.";
                save(s);
                return true;
            }
            else if (result1 == DialogResult.No) { return false; }
            else 
            {
                showEncryptionComplete = false;
                return true; 
            }

        }


        /// <summary>
        /// This method was created for modularity. It is used when the user performs the "Save As" action.
        /// It is also used in saveEncryption().
        /// </summary>
        /// <param name="s">The string intended to be saved to a file.</param>
        private void save(string s)
        {
            DialogResult result2 = saveFileDialog1.ShowDialog();

            if (result2 == DialogResult.OK)
            {
                System.IO.File.WriteAllText(@saveFileDialog1.FileName, s);
            }
            infolabel.Text = "Your Encryption Has Been Saved.";
        }


        /// <summary>
        /// This method converts a byte array into hex and then into a string. It is used in converting the 
        /// MD5 hash into a string. 
        /// </summary>
        /// <param name="b"></param>
        /// <returns>Returns a string form of hex that was converted from a byte array.</returns>
        private string byteToString(byte[] b)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < b.Length; i++)
            {
                sb.Append(b[i].ToString("X2"));
            }
            return sb.ToString(); 
        }


        /// <summary>
        /// This method is used to get the user-defined key for encryption.
        /// </summary>
        /// <returns>Returns the user-defined key as a byte array.</returns>
        private byte[] getKey()
        {
            infolabel.Text = "Please Enter In Your Desired Key/Password";
            string key = Microsoft.VisualBasic.Interaction.InputBox("Please Enter Your Password", "Password Entry", "Default", this.Location.X, this.Location.Y);
            infolabel.Text = "";
            return System.Text.Encoding.Unicode.GetBytes(key);

        }



        /// <summary>
        /// This method is available in order to allow the user the option of opening a file first and then
        /// proceeding with selecting the encryption. The user is not punished if he/she does not open a file
        /// first. The user can select the method of encryption and will be asked what file he/she wants to use
        /// if one has not been selected.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                string temp = getFileName();
                filenameLabel.Text = temp;
                
            }
            catch (IOException x) { infolabel.Text = x.Message; }
       }

        
        /// <summary>
        /// This method opens up a dialog box that is used to select the file that will be encrypted.
        /// It is only meant to get the full path and name of the file.
        /// </summary>
        /// <returns>Returns a string version of the full path and name of the file that will be used.</returns>
        private string getFileName()
        {
            infolabel.Text = "Please Select a File to Encrypt.";
            DialogResult result = openFileDialog1.ShowDialog();
            /*if(result == DialogResult.OK)
            {
                string file = openFileDialog1.FileName;
            }*/
            string file = (result == DialogResult.OK) ? openFileDialog1.FileName : "";
            infolabel.Text = "";
            return file;
        }


        /// <summary>
        /// This function is used to print either just the public or the public and private keys 
        /// to a file.
        /// </summary>
        /// <param name="b">
        /// For the public key only, b = false
        /// For the public & private key, b = true
        /// For more info: http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsa.toxmlstring.aspx#CommunityContent
        /// </param>
        private void printRSA(bool b)
        {
            bool temp = false;
            if(!b)
            {
                DialogResult result = MessageBox.Show("This will save both the public and private key into an XML format. Are you sure you want to continue?", "Continue?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
                if (result == System.Windows.Forms.DialogResult.Yes)
                {
                    temp = true;
                }
            }

            if (b || temp)
            {
                save(RSA.ToXmlString(b).ToString());
            }
        }



        /// <summary>
        /// This method clears out the textbox1
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void resetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            textBox1.Text = filenameLabel.Text = "";
        }



        /// <summary>
        /// All of the following methods call the encrypt() method and pass an assigned integer. This integer
        /// indicates which encyption is to take place.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void mD5ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            encrypt(2);
        }

        private void hMASHA1ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            encrypt(4);
        }

        private void tripleDESToolStripMenuItem_Click(object sender, EventArgs e)
        {
            encrypt(1);
        }

        private void rSAToolStripMenuItem_Click(object sender, EventArgs e)
        {
            encrypt(3);
        }

        
        /// <summary>
        /// This method shows information about the program.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string temp = "This was a three man project. The group members were: Thomas Brookshire Jr. (Developer), Evan Washington (SRS Document), & Drew White (SRS Document).\n\n This project is hosted at code.google.com/p/cs570-artifact-project/ and was a group assignment for CS 570 Advanced Computer Security, taught by Dr. Guillermo Francia III, at Jacksonville State University.\n\n This program was completed on April 12, 2012.";
            MessageBox.Show(temp, "About", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }


        /// <summary>
        /// This method is in place so the user can save any text that is in textBox1, to a file.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            save(textBox1.Text);
        }

        
        /// <summary>
        /// This method is used to simply clear the textBox1 and filenameLabel
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void clearButton_Click(object sender, EventArgs e)
        {
            textBox1.Text = filenameLabel.Text = "";
        }

        
        /// <summary>
        /// This method prints only the public key to a file.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void publicKeyOnlyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            printRSA(false);
        }

        
        /// <summary>
        /// This method prints both the public and private key to a file.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void publicPrivateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            printRSA(true);
        }

        

                
                
    }

}
